Forge
A native implementation of TLS (and various other cryptographic tools) in
JavaScript.
Introduction
The Forge software is a fully native implementation of the TLS protocol
in JavaScript, a set of cryptography utilities, and a set of tools for
developing Web Apps that utilize many network resources.
Performance
Forge is fast. Benchmarks against other popular JavaScript cryptography
libraries can be found here:
Documentation
API
Transports
Ciphers
PKI
Message Digests
Utilities
Other
Installation
Note: Please see the Security Considerations
section before using packaging systems and pre-built files.
Forge uses a CommonJS module structure with a build process for browser
bundles. The older 0.6.x branch with standalone files is available but will
not be regularly updated.
Node.js
If you want to use forge with Node.js, it is available through npm
:
https://npmjs.org/package/node-forge
Installation:
npm install node-forge
You can then use forge as a regular module:
var forge = require('node-forge');
The npm package includes pre-built forge.min.js
, forge.all.min.js
, and
prime.worker.min.js
using the UMD format.
Bundle / Bower
Each release is published in a separate repository as pre-built and minimized
basic forge bundles using the UMD format.
https://github.com/digitalbazaar/forge-dist
This bundle can be used in many environments. In particular it can be installed
with Bower:
bower install forge
jsDelivr CDN
To use it via jsDelivr include this in your html:
<script src="https://cdn.jsdelivr.net/npm/node-forge@0.7.0/dist/forge.min.js"></script>
unpkg CDN
To use it via unpkg include this in your html:
<script src="https://unpkg.com/node-forge@0.7.0/dist/forge.min.js"></script>
Development Requirements
The core JavaScript has the following requirements to build and test:
- Building a browser bundle:
- Testing
- Node.js
- npm
- Chrome, Firefox, Safari (optional)
Some special networking features can optionally use a Flash component. See the
Flash README for details.
Building for a web browser
To create single file bundles for use with browsers run the following:
npm install
npm run build
This will create single non-minimized and minimized files that can be
included in the browser:
dist/forge.js
dist/forge.min.js
A bundle that adds some utilities and networking support is also available:
dist/forge.all.js
dist/forge.all.min.js
Include the file via:
<script src="YOUR_SCRIPT_PATH/forge.js"></script>
or
<script src="YOUR_SCRIPT_PATH/forge.min.js"></script>
The above bundles will synchronously create a global 'forge' object.
Note: These bundles will not include any WebWorker scripts (eg:
dist/prime.worker.js
), so these will need to be accessible from the browser
if any WebWorkers are used.
Building a custom browser bundle
The build process uses webpack and the config file
can be modified to generate a file or files that only contain the parts of
forge you need.
Browserify override support is also present in package.json
.
Testing
Prepare to run tests
npm install
Running automated tests with Node.js
Forge natively runs in a Node.js environment:
npm test
Running automated tests with Headless Chrome
Automated testing is done via Karma. By default it will run the tests with
Headless Chrome.
npm run test-karma
Is 'mocha' reporter output too verbose? Other reporters are available. Try
'dots', 'progress', or 'tap'.
npm run test-karma -- --reporters progress
By default webpack is used. Browserify can also be used.
BUNDLER=browserify npm run test-karma
Running automated tests with one or more browsers
You can also specify one or more browsers to use.
npm run test-karma -- --browsers Chrome,Firefox,Safari,ChromeHeadless
The reporter option and BUNDLER
environment variable can also be used.
Running manual tests in a browser
Testing in a browser uses webpack to combine forge and all tests and then
loading the result in a browser. A simple web server is provided that will
output the HTTP or HTTPS URLs to load. It also will start a simple Flash Policy
Server. Unit tests and older legacy tests are provided. Custom ports can be
used by running node tests/server.js
manually.
To run the unit tests in a browser a special forge build is required:
npm run test-build
To run legacy browser based tests the main forge build is required:
npm run build
The tests are run with a custom server that prints out the URLs to use:
npm run test-server
Running other tests
There are some other random tests and benchmarks available in the tests
directory.
Coverage testing
To perform coverage testing of the unit tests, run the following. The results
will be put in the coverage/
directory. Note that coverage testing can slow
down some tests considerably.
npm install
npm run coverage
Contributing
Any contributions (eg: PRs) that are accepted will be brought under the same
license used by the rest of the Forge project. This license allows Forge to
be used under the terms of either the BSD License or the GNU General Public
License (GPL) Version 2.
See: LICENSE
If a contribution contains 3rd party source code with its own license, it
may retain it, so long as that license is compatible with the Forge license.
API
Options
If at any time you wish to disable the use of native code, where available,
for particular forge features like its secure random number generator, you
may set the forge.options.usePureJavaScript
flag to true
. It is
not recommended that you set this flag as native code is typically more
performant and may have stronger security properties. It may be useful to
set this flag to test certain features that you plan to run in environments
that are different from your testing environment.
To disable native code when including forge in the browser:
forge.options.usePureJavaScript = true;
To disable native code when using Node.js:
var forge = require('node-forge');
forge.options.usePureJavaScript = true;
Transports
TLS
Provides a native javascript client and server-side TLS implementation.
Examples
var client = forge.tls.createConnection({
server: false,
caStore: ,
sessionCache: {},
cipherSuites: [
forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA,
forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA],
virtualHost: 'example.com',
verify: function(connection, verified, depth, certs) {
if(depth === 0) {
var cn = certs[0].subject.getField('CN').value;
if(cn !== 'example.com') {
verified = {
alert: forge.tls.Alert.Description.bad_certificate,
message: 'Certificate common name does not match hostname.'
};
}
}
return verified;
},
connected: function(connection) {
console.log('connected');
connection.prepare(forge.util.encodeUtf8('Hi server!'));
},
getPrivateKey: function(connection, cert) {
return myClientPrivateKey;
},
tlsDataReady: function(connection) {
sendToServerSomehow(connection.tlsData.getBytes());
},
dataReady: function(connection) {
console.log('the server sent: ' +
forge.util.decodeUtf8(connection.data.getBytes()));
connection.close();
},
closed: function(connection) {
console.log('disconnected');
},
error: function(connection, error) {
console.log('uh oh', error);
}
});
client.handshake();
client.process(encryptedBytesFromServer);
var server = forge.tls.createConnection({
server: true,
caStore: ,
sessionCache: {},
cipherSuites: [
forge.tls.CipherSuites.TLS_RSA_WITH_AES_128_CBC_SHA,
forge.tls.CipherSuites.TLS_RSA_WITH_AES_256_CBC_SHA],
verifyClient: true,
verify: function(connection, verified, depth, certs) {
if(depth === 0) {
var cn = certs[0].subject.getField('CN').value;
if(cn !== 'the-client') {
verified = {
alert: forge.tls.Alert.Description.bad_certificate,
message: 'Certificate common name does not match expected client.'
};
}
}
return verified;
},
connected: function(connection) {
console.log('connected');
connection.prepare(forge.util.encodeUtf8('Hi client!'));
},
getCertificate: function(connection, hint) {
return myServerCertificate;
},
getPrivateKey: function(connection, cert) {
return myServerPrivateKey;
},
tlsDataReady: function(connection) {
sendToClientSomehow(connection.tlsData.getBytes());
},
dataReady: function(connection) {
console.log('the client sent: ' +
forge.util.decodeUtf8(connection.data.getBytes()));
connection.close();
},
closed: function(connection) {
console.log('disconnected');
},
error: function(connection, error) {
console.log('uh oh', error);
}
});
server.process(encryptedBytesFromClient);
Connect to a TLS server using node's net.Socket:
var socket = new net.Socket();
var client = forge.tls.createConnection({
server: false,
verify: function(connection, verified, depth, certs) {
console.log('[tls] server certificate verified');
return true;
},
connected: function(connection) {
console.log('[tls] connected');
client.prepare('GET / HTTP/1.0\r\n\r\n');
},
tlsDataReady: function(connection) {
var data = connection.tlsData.getBytes();
socket.write(data, 'binary');
},
dataReady: function(connection) {
var data = connection.data.getBytes();
console.log('[tls] data received from the server: ' + data);
},
closed: function() {
console.log('[tls] disconnected');
},
error: function(connection, error) {
console.log('[tls] error', error);
}
});
socket.on('connect', function() {
console.log('[socket] connected');
client.handshake();
});
socket.on('data', function(data) {
client.process(data.toString('binary'));
});
socket.on('end', function() {
console.log('[socket] disconnected');
});
socket.connect(443, 'google.com');
HTTP
Provides a native JavaScript mini-implementation of an http client that
uses pooled sockets.
Examples
var request = forge.http.createRequest({method: 'GET', path: url.path});
sendSomehow(request.toString());
var buffer = forge.util.createBuffer();
var response = forge.http.createResponse();
var someAsyncDataHandler = function(bytes) {
if(!response.bodyReceived) {
buffer.putBytes(bytes);
if(!response.headerReceived) {
if(response.readHeader(buffer)) {
console.log('HTTP response header: ' + response.toString());
}
}
if(response.headerReceived && !response.bodyReceived) {
if(response.readBody(buffer)) {
console.log('HTTP response body: ' + response.body);
}
}
}
};
SSH
Provides some SSH utility functions.
Examples
forge.ssh.privateKeyToPutty(privateKey, passphrase, comment);
forge.ssh.publicKeyToOpenSSH(key, comment);
forge.ssh.privateKeyToOpenSSH(privateKey, passphrase);
forge.ssh.getPublicKeyFingerprint(key);
forge.ssh.getPublicKeyFingerprint(key, {encoding: 'hex', delimiter: ':'});
XHR
Provides an XmlHttpRequest implementation using forge.http as a backend.
Examples
Sockets
Provides an interface to create and use raw sockets provided via Flash.
Examples
Ciphers
CIPHER
Provides a basic API for block encryption and decryption. There is built-in
support for the ciphers: AES, 3DES, and DES, and for the modes
of operation: ECB, CBC, CFB, OFB, CTR, and GCM.
These algorithms are currently supported:
- AES-ECB
- AES-CBC
- AES-CFB
- AES-OFB
- AES-CTR
- AES-GCM
- 3DES-ECB
- 3DES-CBC
- DES-ECB
- DES-CBC
When using an AES algorithm, the key size will determine whether
AES-128, AES-192, or AES-256 is used (all are supported). When a DES
algorithm is used, the key size will determine whether 3DES or regular
DES is used. Use a 3DES algorithm to enforce Triple-DES.
Examples
var key = forge.random.getBytesSync(16);
var iv = forge.random.getBytesSync(16);
var cipher = forge.cipher.createCipher('AES-CBC', key);
cipher.start({iv: iv});
cipher.update(forge.util.createBuffer(someBytes));
cipher.finish();
var encrypted = cipher.output;
console.log(encrypted.toHex());
var decipher = forge.cipher.createDecipher('AES-CBC', key);
decipher.start({iv: iv});
decipher.update(encrypted);
var result = decipher.finish();
console.log(decipher.output.toHex());
var encryptedBytes = encrypted.bytes();
var decipher = forge.cipher.createDecipher('AES-CBC', key);
decipher.start({iv: iv});
var length = encryptedBytes.length;
var chunkSize = 1024 * 64;
var index = 0;
var decrypted = '';
do {
decrypted += decipher.output.getBytes();
var buf = forge.util.createBuffer(encryptedBytes.substr(index, chunkSize));
decipher.update(buf);
index += chunkSize;
} while(index < length);
var result = decipher.finish();
assert(result);
decrypted += decipher.output.getBytes();
console.log(forge.util.bytesToHex(decrypted));
var cipher = forge.cipher.createCipher('AES-GCM', key);
cipher.start({
iv: iv,
additionalData: 'binary-encoded string',
tagLength: 128
});
cipher.update(forge.util.createBuffer(someBytes));
cipher.finish();
var encrypted = cipher.output;
var tag = cipher.mode.tag;
console.log(encrypted.toHex());
console.log(tag.toHex());
var decipher = forge.cipher.createDecipher('AES-GCM', key);
decipher.start({
iv: iv,
additionalData: 'binary-encoded string',
tagLength: 128,
tag: tag
});
decipher.update(encrypted);
var pass = decipher.finish();
if(pass) {
console.log(decipher.output.toHex());
}
Using forge in Node.js to match openssl's "enc" command line tool (Note: OpenSSL "enc" uses a non-standard file format with a custom key derivation function and a fixed iteration count of 1, which some consider less secure than alternatives such as OpenPGP/GnuPG):
var forge = require('node-forge');
var fs = require('fs');
function encrypt(password) {
var input = fs.readFileSync('input.txt', {encoding: 'binary'});
var keySize = 24;
var ivSize = 8;
var salt = forge.random.getBytesSync(8);
var derivedBytes = forge.pbe.opensslDeriveBytes(
password, salt, keySize + ivSize);
var buffer = forge.util.createBuffer(derivedBytes);
var key = buffer.getBytes(keySize);
var iv = buffer.getBytes(ivSize);
var cipher = forge.cipher.createCipher('3DES-CBC', key);
cipher.start({iv: iv});
cipher.update(forge.util.createBuffer(input, 'binary'));
cipher.finish();
var output = forge.util.createBuffer();
if(salt !== null) {
output.putBytes('Salted__');
output.putBytes(salt);
}
output.putBuffer(cipher.output);
fs.writeFileSync('input.enc', output.getBytes(), {encoding: 'binary'});
}
function decrypt(password) {
var input = fs.readFileSync('input.enc', {encoding: 'binary'});
input = forge.util.createBuffer(input, 'binary');
input.getBytes('Salted__'.length);
var salt = input.getBytes(8);
var keySize = 24;
var ivSize = 8;
var derivedBytes = forge.pbe.opensslDeriveBytes(
password, salt, keySize + ivSize);
var buffer = forge.util.createBuffer(derivedBytes);
var key = buffer.getBytes(keySize);
var iv = buffer.getBytes(ivSize);
var decipher = forge.cipher.createDecipher('3DES-CBC', key);
decipher.start({iv: iv});
decipher.update(input);
var result = decipher.finish();
fs.writeFileSync(
'input.dec.txt', decipher.output.getBytes(), {encoding: 'binary'});
}
AES
Provides AES encryption and decryption in CBC, CFB, OFB,
CTR, and GCM modes. See CIPHER for examples.
DES
Provides 3DES and DES encryption and decryption in ECB and
CBC modes. See CIPHER for examples.
RC2
Examples
var key = forge.random.getBytesSync(16);
var iv = forge.random.getBytesSync(8);
var cipher = forge.rc2.createEncryptionCipher(key);
cipher.start(iv);
cipher.update(forge.util.createBuffer(someBytes));
cipher.finish();
var encrypted = cipher.output;
console.log(encrypted.toHex());
var cipher = forge.rc2.createDecryptionCipher(key);
cipher.start(iv);
cipher.update(encrypted);
cipher.finish();
console.log(cipher.output.toHex());
PKI
Provides X.509 certificate support, ED25519 key generation and
signing/verifying, and RSA public and private key encoding, decoding,
encryption/decryption, and signing/verifying.
ED25519
Special thanks to TweetNaCl.js for providing the bulk of the implementation.
Examples
var ed25519 = forge.pki.ed25519;
var keypair = ed25519.generateKeyPair();
var seed = forge.random.getBytesSync(32);
var keypair = ed25519.generateKeyPair({seed: seed});
var password = 'Mai9ohgh6ahxee0jutheew0pungoozil';
var seed = new forge.util.ByteBuffer(password, 'utf8');
var keypair = ed25519.generateKeyPair({seed: seed});
var signature = ED25519.sign({
message: 'test',
encoding: 'utf8',
privateKey: privateKey
});
var signature = ED25519.sign({
message: Buffer.from('test', 'utf8'),
privateKey: privateKey
});
var md = forge.md.sha256.create();
md.update('test', 'utf8');
var signature = ED25519.sign({
md: md,
privateKey: privateKey
});
var verified = ED25519.verify({
message: 'test',
encoding: 'utf8',
signature: signature,
publicKey: publicKey
});
var verified = ED25519.verify({
message: Buffer.from('test', 'utf8'),
signature: signature,
publicKey: publicKey
});
var md = forge.md.sha256.create();
md.update('test', 'utf8');
var verified = ED25519.verify({
md: md,
signature: signature,
publicKey: publicKey
});
RSA
Examples
var rsa = forge.pki.rsa;
var keypair = rsa.generateKeyPair({bits: 2048, e: 0x10001});
rsa.generateKeyPair({bits: 2048, workers: 2}, function(err, keypair) {
});
var state = rsa.createKeyPairGenerationState(2048, 0x10001);
var step = function() {
if(!rsa.stepKeyPairGenerationState(state, 100)) {
setTimeout(step, 1);
}
else {
}
};
setTimeout(step);
var md = forge.md.sha1.create();
md.update('sign this', 'utf8');
var signature = privateKey.sign(md);
var verified = publicKey.verify(md.digest().bytes(), signature);
var md = forge.md.sha1.create();
md.update('sign this', 'utf8');
var pss = forge.pss.create({
md: forge.md.sha1.create(),
mgf: forge.mgf.mgf1.create(forge.md.sha1.create()),
saltLength: 20
});
var signature = privateKey.sign(md, pss);
var pss = forge.pss.create({
md: forge.md.sha1.create(),
mgf: forge.mgf.mgf1.create(forge.md.sha1.create()),
saltLength: 20
});
var md = forge.md.sha1.create();
md.update('sign this', 'utf8');
publicKey.verify(md.digest().getBytes(), signature, pss);
var encrypted = publicKey.encrypt(bytes);
var decrypted = privateKey.decrypt(encrypted);
var encrypted = publicKey.encrypt(bytes, 'RSAES-PKCS1-V1_5');
var decrypted = privateKey.decrypt(encrypted, 'RSAES-PKCS1-V1_5');
var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP');
var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP');
var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', {
md: forge.md.sha256.create()
});
var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', {
md: forge.md.sha256.create()
});
var encrypted = publicKey.encrypt(bytes, 'RSA-OAEP', {
md: forge.md.sha256.create(),
mgf1: {
md: forge.md.sha1.create()
}
});
var decrypted = privateKey.decrypt(encrypted, 'RSA-OAEP', {
md: forge.md.sha256.create(),
mgf1: {
md: forge.md.sha1.create()
}
});
RSA-KEM
Examples
forge.rsa.generateKeyPair({bits: 2048, workers: -1}, function(err, keypair) {
});
var kdf1 = new forge.kem.kdf1(forge.md.sha1.create());
var kem = forge.kem.rsa.create(kdf1);
var result = kem.encrypt(keypair.publicKey, 16);
var iv = forge.random.getBytesSync(12);
var someBytes = 'hello world!';
var cipher = forge.cipher.createCipher('AES-GCM', result.key);
cipher.start({iv: iv});
cipher.update(forge.util.createBuffer(someBytes));
cipher.finish();
var encrypted = cipher.output.getBytes();
var tag = cipher.mode.tag.getBytes();
var kdf1 = new forge.kem.kdf1(forge.md.sha1.create());
var kem = forge.kem.rsa.create(kdf1);
var key = kem.decrypt(keypair.privateKey, result.encapsulation, 16);
var decipher = forge.cipher.createDecipher('AES-GCM', key);
decipher.start({iv: iv, tag: tag});
decipher.update(forge.util.createBuffer(encrypted));
var pass = decipher.finish();
if(pass) {
console.log(decipher.output.getBytes());
}
X.509
Examples
var pki = forge.pki;
var publicKey = pki.publicKeyFromPem(pem);
var pem = pki.publicKeyToPem(publicKey);
var publicKey = pki.publicKeyFromAsn1(subjectPublicKeyInfo);
var subjectPublicKeyInfo = pki.publicKeyToAsn1(publicKey);
pki.getPublicKeyFingerprint(key);
pki.getPublicKeyFingerprint(key, {type: 'SubjectPublicKeyInfo'});
pki.getPublicKeyFingerprint(key, {encoding: 'hex', delimiter: ':'});
pki.getPublicKeyFingerprint(key, {
type: 'SubjectPublicKeyInfo',
encoding: 'hex',
delimiter: ':'
});
pki.getPublicKeyFingerprint(key, {
md: forge.md.md5.create(),
encoding: 'hex',
delimiter: ':'
});
var caStore = pki.createCaStore([, ...]);
caStore.addCertificate(certObjectOrPemString);
var issuerCert = caStore.getIssuer(subjectCert);
pki.verifyCertificateChain(caStore, chain, customVerifyCallback);
cert.sign(privateKey);
cert.sign(privateKey, forge.md.sha256.create());
var verified = issuer.verify(issued);
var keys = pki.rsa.generateKeyPair(2048);
var cert = pki.createCertificate();
cert.publicKey = keys.publicKey;
cert.serialNumber = '01';
cert.validity.notBefore = new Date();
cert.validity.notAfter = new Date();
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1);
var attrs = [{
name: 'commonName',
value: 'example.org'
}, {
name: 'countryName',
value: 'US'
}, {
shortName: 'ST',
value: 'Virginia'
}, {
name: 'localityName',
value: 'Blacksburg'
}, {
name: 'organizationName',
value: 'Test'
}, {
shortName: 'OU',
value: 'Test'
}];
cert.setSubject(attrs);
cert.setIssuer(attrs);
cert.setExtensions([{
name: 'basicConstraints',
cA: true
}, {
name: 'keyUsage',
keyCertSign: true,
digitalSignature: true,
nonRepudiation: true,
keyEncipherment: true,
dataEncipherment: true
}, {
name: 'extKeyUsage',
serverAuth: true,
clientAuth: true,
codeSigning: true,
emailProtection: true,
timeStamping: true
}, {
name: 'nsCertType',
client: true,
server: true,
email: true,
objsign: true,
sslCA: true,
emailCA: true,
objCA: true
}, {
name: 'subjectAltName',
altNames: [{
type: 6,
value: 'http://example.org/webid#me'
}, {
type: 7,
ip: '127.0.0.1'
}]
}, {
name: 'subjectKeyIdentifier'
}]);
cert.sign(keys.privateKey);
var pem = pki.certificateToPem(cert);
var cert = pki.certificateFromPem(pem);
var cert = pki.certificateFromAsn1(obj);
var asn1Cert = pki.certificateToAsn1(cert);
PKCS#5
Provides the password-based key-derivation function from PKCS#5.
Examples
var salt = forge.random.getBytesSync(128);
var derivedKey = forge.pkcs5.pbkdf2('password', salt, numIterations, 16);
forge.pkcs5.pbkdf2('password', salt, numIterations, 16, function(err, derivedKey) {
});
PKCS#7
Provides cryptographically protected messages from PKCS#7.
Examples
var p7 = forge.pkcs7.messageFromPem(pem);
var recipient = p7.findRecipient(cert);
p7.decrypt(p7.recipients[0], privateKey);
var p7 = forge.pkcs7.createEnvelopedData();
var cert = forge.pki.certificateFromPem(certPem);
p7.addRecipient(cert);
p7.content = forge.util.createBuffer('Hello');
p7.encrypt();
var pem = forge.pkcs7.messageToPem(p7);
var p7 = forge.pkcs7.createSignedData();
p7.addCertificate(certOrCertPem1);
p7.addCertificate(certOrCertPem2);
var pem = forge.pkcs7.messageToPem(p7);
var p7 = forge.pkcs7.createSignedData();
p7.content = forge.util.createBuffer('Some content to be signed.', 'utf8');
p7.addCertificate(certOrCertPem);
p7.addSigner({
key: privateKeyAssociatedWithCert,
certificate: certOrCertPem,
digestAlgorithm: forge.pki.oids.sha256,
authenticatedAttributes: [{
type: forge.pki.oids.contentType,
value: forge.pki.oids.data
}, {
type: forge.pki.oids.messageDigest
}, {
type: forge.pki.oids.signingTime,
value: new Date()
}]
});
p7.sign();
var pem = forge.pkcs7.messageToPem(p7);
p7.sign({detached: true});
PKCS#8
Examples
var pki = forge.pki;
var privateKey = pki.privateKeyFromPem(pem);
var pem = pki.privateKeyToPem(privateKey);
var privateKey = pki.privateKeyFromAsn1(rsaPrivateKey);
var rsaPrivateKey = pki.privateKeyToAsn1(privateKey);
var privateKeyInfo = pki.wrapRsaPrivateKey(rsaPrivateKey);
var pem = pki.privateKeyInfoToPem(privateKeyInfo);
var encryptedPrivateKeyInfo = pki.encryptPrivateKeyInfo(
privateKeyInfo, 'myCustomPasswordHere', {
algorithm: 'aes256',
});
var privateKeyInfo = pki.decryptPrivateKeyInfo(
encryptedPrivateKeyInfo, 'myCustomPasswordHere');
var pem = pki.encryptedPrivateKeyToPem(encryptedPrivateKeyInfo);
var encryptedPrivateKeyInfo = pki.encryptedPrivateKeyFromPem(pem);
var pem = pki.encryptRsaPrivateKey(privateKey, 'password');
var pem = pki.encryptRsaPrivateKey(privateKey, 'password', {legacy: true});
var privateKey = pki.decryptRsaPrivateKey(pem, 'password');
var publicKey = pki.setRsaPublicKey(privateKey.n, privateKey.e);
PKCS#10
Provides certification requests or certificate signing requests (CSR) from
PKCS#10.
Examples
var keys = forge.pki.rsa.generateKeyPair(1024);
var csr = forge.pki.createCertificationRequest();
csr.publicKey = keys.publicKey;
csr.setSubject([{
name: 'commonName',
value: 'example.org'
}, {
name: 'countryName',
value: 'US'
}, {
shortName: 'ST',
value: 'Virginia'
}, {
name: 'localityName',
value: 'Blacksburg'
}, {
name: 'organizationName',
value: 'Test'
}, {
shortName: 'OU',
value: 'Test'
}]);
csr.setAttributes([{
name: 'challengePassword',
value: 'password'
}, {
name: 'unstructuredName',
value: 'My Company, Inc.'
}, {
name: 'extensionRequest',
extensions: [{
name: 'subjectAltName',
altNames: [{
type: 2,
value: 'test.domain.com'
}, {
type: 2,
value: 'other.domain.com',
}, {
type: 2,
value: 'www.domain.net'
}]
}]
}]);
csr.sign(keys.privateKey);
var verified = csr.verify();
var pem = forge.pki.certificationRequestToPem(csr);
var csr = forge.pki.certificationRequestFromPem(pem);
csr.getAttribute({name: 'challengePassword'});
csr.getAttribute({name: 'extensionRequest'}).extensions;
PKCS#12
Provides the cryptographic archive file format from PKCS#12.
Note for Chrome/Firefox/iOS/similar users: If you have trouble importing
a PKCS#12 container, try using the TripleDES algorithm. It can be passed
to forge.pkcs12.toPkcs12Asn1
using the {algorithm: '3des'}
option.
Examples
var p12Der = forge.util.decode64(p12b64);
var p12Asn1 = forge.asn1.fromDer(p12Der);
var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, 'password');
var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, false, 'password');
var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1);
var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, '');
var bags = p12.getBags({friendlyName: 'test'});
var cert = bags.friendlyName[0];
var bags = p12.getBags({localKeyId: buffer});
var cert = bags.localKeyId[0];
var bags = p12.getBags({localKeyIdHex: '7b59377ff142d0be4565e9ac3d396c01401cd879'});
var cert = bags.localKeyId[0];
var bags = p12.getBags({bagType: forge.pki.oids.certBag});
var cert = bags[forge.pki.oids.certBag][0];
var bags = p12.getBags({
friendlyName: 'test',
bagType: forge.pki.oids.certBag
});
var bags = p12.getBags({bagType: forge.pki.oids.keyBag});
var bag = bags[forge.pki.oids.keyBag][0];
var key = bag.key;
if(bag.key === null) {
var keyAsn1 = bag.asn1;
}
var p12Asn1 = forge.pkcs12.toPkcs12Asn1(
privateKey, certificateChain, 'password');
var p12Asn1 = forge.pkcs12.toPkcs12Asn1(
privateKey, certificateChain, 'password',
{algorithm: '3des'});
var p12Der = forge.asn1.toDer(p12Asn1).getBytes();
var p12b64 = forge.util.encode64(p12Der);
var a = document.createElement('a');
a.download = 'example.p12';
a.setAttribute('href', 'data:application/x-pkcs12;base64,' + p12b64);
a.appendChild(document.createTextNode('Download'));
ASN.1
Provides ASN.1 DER encoding and decoding.
Examples
var asn1 = forge.asn1;
var subjectPublicKeyInfo =
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.OID, false,
asn1.oidToDer(pki.oids['rsaEncryption']).getBytes()),
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '')
]),
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.SEQUENCE, true, [
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
_bnToBytes(key.n)),
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false,
_bnToBytes(key.e))
])
])
]);
var derBuffer = asn1.toDer(subjectPublicKeyInfo);
var object = asn1.fromDer(derBuffer);
var derOidBuffer = asn1.oidToDer('1.2.840.113549.1.1.5');
console.log(asn1.derToOid(derOidBuffer));
var publicKeyValidator = {
name: 'SubjectPublicKeyInfo',
tagClass: asn1.Class.UNIVERSAL,
type: asn1.Type.SEQUENCE,
constructed: true,
captureAsn1: 'subjectPublicKeyInfo',
value: [{
name: 'SubjectPublicKeyInfo.AlgorithmIdentifier',
tagClass: asn1.Class.UNIVERSAL,
type: asn1.Type.SEQUENCE,
constructed: true,
value: [{
name: 'AlgorithmIdentifier.algorithm',
tagClass: asn1.Class.UNIVERSAL,
type: asn1.Type.OID,
constructed: false,
capture: 'publicKeyOid'
}]
}, {
name: 'SubjectPublicKeyInfo.subjectPublicKey',
tagClass: asn1.Class.UNIVERSAL,
type: asn1.Type.BITSTRING,
constructed: false,
value: [{
name: 'SubjectPublicKeyInfo.subjectPublicKey.RSAPublicKey',
tagClass: asn1.Class.UNIVERSAL,
type: asn1.Type.SEQUENCE,
constructed: true,
optional: true,
captureAsn1: 'rsaPublicKey'
}]
}]
};
var capture = {};
var errors = [];
if(!asn1.validate(
publicKeyValidator, subjectPublicKeyInfo, validator, capture, errors)) {
throw 'ASN.1 object is not a SubjectPublicKeyInfo.';
}
var oid = asn1.derToOid(capture.publicKeyOid);
if(oid !== pki.oids['rsaEncryption']) {
throw 'Unsupported OID.';
}
asn1.prettyPrint(object);
Message Digests
SHA1
Provides SHA-1 message digests.
Examples
var md = forge.md.sha1.create();
md.update('The quick brown fox jumps over the lazy dog');
console.log(md.digest().toHex());
SHA256
Provides SHA-256 message digests.
Examples
var md = forge.md.sha256.create();
md.update('The quick brown fox jumps over the lazy dog');
console.log(md.digest().toHex());
SHA384
Provides SHA-384 message digests.
Examples
var md = forge.md.sha384.create();
md.update('The quick brown fox jumps over the lazy dog');
console.log(md.digest().toHex());
SHA512
Provides SHA-512 message digests.
Examples
var md = forge.md.sha512.create();
md.update('The quick brown fox jumps over the lazy dog');
console.log(md.digest().toHex());
var md = forge.md.sha512.sha224.create();
md.update('The quick brown fox jumps over the lazy dog');
console.log(md.digest().toHex());
var md = forge.md.sha512.sha256.create();
md.update('The quick brown fox jumps over the lazy dog');
console.log(md.digest().toHex());
MD5
Provides MD5 message digests.
Examples
var md = forge.md.md5.create();
md.update('The quick brown fox jumps over the lazy dog');
console.log(md.digest().toHex());
HMAC
Provides HMAC w/any supported message digest algorithm.
Examples
var hmac = forge.hmac.create();
hmac.start('sha1', 'Jefe');
hmac.update('what do ya want for nothing?');
console.log(hmac.digest().toHex());
Utilities
Prime
Provides an API for generating large, random, probable primes.
Examples
var bits = 1024;
forge.prime.generateProbablePrime(bits, function(err, num) {
console.log('random prime', num.toString(16));
});
var bits = 1024;
var options = {
algorithm: {
name: 'PRIMEINC',
workers: -1
}
};
forge.prime.generateProbablePrime(bits, options, function(err, num) {
console.log('random prime', num.toString(16));
});
PRNG
Provides a Fortuna-based cryptographically-secure pseudo-random number
generator, to be used with a cryptographic function backend, e.g. AES. An
implementation using AES as a backend is provided. An API for collecting
entropy is given, though if window.crypto.getRandomValues is available, it will
be used automatically.
Examples
var bytes = forge.random.getBytesSync(32);
console.log(forge.util.bytesToHex(bytes));
forge.random.getBytes(32, function(err, bytes) {
console.log(forge.util.bytesToHex(bytes));
});
forge.random.collect(someRandomBytes);
jQuery().mousemove(function(e) {
forge.random.collectInt(e.clientX, 16);
forge.random.collectInt(e.clientY, 16);
});
forge.random.seedFileSync = function(needed) {
return fetchedRandomBytes;
};
forge.random.seedFile = function(needed, callback) {
callback(null, fetchedRandomBytes);
});
forge.random.registerWorker(self);
var myPrng = forge.random.createInstance();
Tasks
Provides queuing and synchronizing tasks in a web application.
Examples
Utilities
Provides utility functions, including byte buffer support, base64,
bytes to/from hex, zlib inflate/deflate, etc.
Examples
var encoded = forge.util.encode64(str);
var str = forge.util.decode64(encoded);
var encoded = forge.util.encodeUtf8(str);
var str = forge.util.decodeUtf8(encoded);
var bytes = forge.util.hexToBytes(hex);
var hex = forge.util.bytesToHex(bytes);
var buffer = forge.util.createBuffer();
var buffer = forge.util.createBuffer(input, 'raw');
var buffer = forge.util.createBuffer(input, 'utf8');
buffer.length();
buffer.putBytes(bytes);
buffer.putInt32(10);
buffer.toHex();
bytes.bytes();
bytes.getBytes();
var forgeBuffer = forge.util.createBuffer();
var nodeBuffer = Buffer.from(forgeBuffer.getBytes(), 'binary');
var nodeBuffer = Buffer.from('CAFE', 'hex');
var forgeBuffer = forge.util.createBuffer(nodeBuffer.toString('binary'));
var parsed = forge.util.parseUrl('http://example.com/foo?bar=baz');
Logging
Provides logging to a javascript console using various categories and
levels of verbosity.
Examples
Debugging
Provides storage of debugging information normally inaccessible in
closures for viewing/investigation.
Examples
Flash Networking Support
The flash README provides details on rebuilding the
optional Flash component used for networking. It also provides details on
Policy Server support.
Security Considerations
When using this code please keep the following in mind:
- Cryptography is hard. Please review and test this code before depending on it
for critical functionality.
- The nature of JavaScript is that execution of this code depends on trusting a
very large set of JavaScript tools and systems. Consider runtime variations,
runtime characteristics, runtime optimization, code optimization, code
minimization, code obfuscation, bundling tools, possible bugs, the Forge code
itself, and so on.
- If using pre-built bundles from Bower or similar be aware someone else
ran the tools to create those files.
- Use a secure transport channel such as TLS to load scripts and consider
using additional security mechanisms such as Subresource Integrity script
attributes.
- Use "native" functionality where possible. This can be critical when dealing
with performance and random number generation. Note that the JavaScript
random number algorithms should perform well if given suitable entropy.
- Understand possible attacks against cryptographic systems. For instance side
channel and timing attacks may be possible due to the difficulty in
implementing constant time algorithms in pure JavaScript.
- Certain features in this library are less susceptible to attacks depending on
usage. This primarily includes features that deal with data format
manipulation or those that are not involved in communication.
- Do not pass unsafe inputs to
util.setPath
. Doing so could expose a
prototype pollution security issue.
Library Background
Contact
Donations
Financial support is welcome and helps contribute to futher development: